package com.dapeng.cleardatabackend.controller;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dapeng.cleardatabackend.annotation.AuthCheck;
import com.dapeng.cleardatabackend.common.BaseResponse;
import com.dapeng.cleardatabackend.common.ErrorCode;
import com.dapeng.cleardatabackend.common.LoginUserHolder;
import com.dapeng.cleardatabackend.common.ResultUtils;
import com.dapeng.cleardatabackend.exception.ThrowUtils;
import com.dapeng.cleardatabackend.model.dto.user.*;
import com.dapeng.cleardatabackend.model.entity.User;
import com.dapeng.cleardatabackend.model.enums.UserRoleEnum;
import com.dapeng.cleardatabackend.model.vo.UserVO;
import com.dapeng.cleardatabackend.service.UserService;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.dapeng.cleardatabackend.contant.UserConstant.USER_ACCOUNT_REGEX;
import static com.dapeng.cleardatabackend.contant.UserConstant.USER_LOGIN_STATE;


/**
 * 用户控制层
 *
 * @author dapeng
 */
@RestController
@RequestMapping("/user")
@Api(tags = "用户模块")
public class UserController {

    @Resource
    private UserService userService;

    /**
     * 用户注册
     *
     * @param userRegisterRequest 用户注册请求
     * @return {@link BaseResponse }<{@link Long }>
     */
    @PostMapping("/register")
    public BaseResponse<Long> userRegister(@RequestBody @Valid UserRegisterRequest userRegisterRequest) {
        String userAccount = userRegisterRequest.getUserAccount();
        String userPassword = userRegisterRequest.getUserPassword();
        String checkPassword = userRegisterRequest.getCheckPassword();
        if (checkPassword != null) {
            ThrowUtils.throwIf(!userPassword.equals(checkPassword), ErrorCode.PARAMS_ERROR, "两次输入的密码不一致");
        }
        Matcher matcher = Pattern.compile(USER_ACCOUNT_REGEX).matcher(userAccount);
        ThrowUtils.throwIf(matcher.find(), ErrorCode.PARAMS_ERROR, "账户不能包含特殊字符");
        long result = userService.userRegister(userRegisterRequest);
        return ResultUtils.success(result);
    }


    /**
     * 用户登录
     *
     * @param userLoginRequest 用户登录请求
     * @param request          请求
     * @return {@link BaseResponse }<{@link UserVO }>
     */
    @PostMapping("/login")
    public BaseResponse<UserVO> userLogin(@RequestBody @Valid UserLoginRequest userLoginRequest, HttpServletRequest request) {
        UserVO user = userService.userLogin(userLoginRequest, request);
        return ResultUtils.success(user);
    }


    /**
     * 用户注销
     *
     * @param request 请求
     * @return {@link BaseResponse }<{@link Boolean }>
     */
    @PostMapping("/logout")
    public BaseResponse<Boolean> userLogout(HttpServletRequest request) {
        return ResultUtils.success(userService.userLogout(request));
    }

    /**
     * 获取当前用户
     *
     * @return {@link BaseResponse }<{@link UserVO }>
     */
    @GetMapping("/current")
    public BaseResponse<UserVO> getCurrentUser(HttpServletRequest request) {
        User currUser = LoginUserHolder.getLoginUser();
        long userId = currUser.getId();
        // TODO 校验用户是否合法
        User user = userService.getById(userId);
        ThrowUtils.throwIf(user == null, ErrorCode.OPERATION_ERROR, "当前用户不存在");
        ThrowUtils.throwIf(user.getUserRole() == UserRoleEnum.BAN, ErrorCode.OPERATION_ERROR, "该用户已被封禁");
        request.getSession().setAttribute(USER_LOGIN_STATE, user);
        LoginUserHolder.setLoginUser(user);
        return ResultUtils.success(UserVO.objectToVO(user));
    }

    /**
     * 更新密码
     *
     * @param userUpdatePasswordRequest 用户更新密码请求
     * @return {@link BaseResponse }<{@link Boolean }>
     */
    @PostMapping("/password")
    public BaseResponse<Boolean> updatePassword(@RequestBody @Valid UserUpdatePasswordRequest userUpdatePasswordRequest) {
        if (userUpdatePasswordRequest.getCheckPassword() != null) {
            ThrowUtils.throwIf(!userUpdatePasswordRequest.getUserPassword().equals(userUpdatePasswordRequest.getCheckPassword()),
                    ErrorCode.OPERATION_ERROR, "两次输入的密码不一致");
        }
        boolean result = userService.updatePassword(userUpdatePasswordRequest);
        return ResultUtils.success(result);
    }

    /**
     * 搜索用户
     *
     * @param userSearchRequest 用户搜索请求
     * @return {@link BaseResponse }<{@link Page }<{@link UserVO }>>
     */
    @PostMapping("/page")
    @AuthCheck(mustRole = UserRoleEnum.ADMIN)
    public BaseResponse<Page<UserVO>> getUserPage(@RequestBody UserSearchRequest userSearchRequest) {
        Page<UserVO> userPage = userService.searchUsers(userSearchRequest);
        return ResultUtils.success(userPage);
    }

    /**
     * 删除用户
     *
     * @param id 身份证件
     * @return {@link BaseResponse }<{@link Boolean }>
     */
    @PostMapping("/delete/{id}")
    @AuthCheck(mustRole = UserRoleEnum.ADMIN)
    public BaseResponse<Boolean> deleteUsers(@PathVariable("id") long id) {
        ThrowUtils.throwIf(!userService.removeById(id), ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(true);
    }


    /**
     * 更新用户
     *
     * @param userUpdateMyRequest 更新用户请求
     * @return {@link BaseResponse }<{@link Boolean }>
     */
    @PostMapping("/update")
    public BaseResponse<Boolean> updateUsers(@RequestBody @Valid UserUpdateMyRequest userUpdateMyRequest) {
        ThrowUtils.throwIf(BeanUtil.isEmpty(userUpdateMyRequest), ErrorCode.OPERATION_ERROR, "请传入修改值");
        return ResultUtils.success(userService.updateUser(userUpdateMyRequest));
    }

    /**
     * 更新用户访问权限
     *
     * @param userUpdateAccessRequest 用户更新访问请求
     * @return {@link BaseResponse }<{@link Boolean }>
     */
    @PostMapping("/admin/update")
    @AuthCheck(mustRole = UserRoleEnum.SUPER_ADMIN)
    public BaseResponse<Boolean> updateUserAccess(@RequestBody @Valid UserUpdateAccessRequest userUpdateAccessRequest) {
        return ResultUtils.success(userService.updateUserAccess(userUpdateAccessRequest));
    }
}
